#include "i2c.h"
#include "nau88c22.h"
#include "types.h"
#include "DrvUART010.h"

static const int update_reg[] = {
	NAU88C22_LEFT_DAC_DIGITAL_VOLUME,
	NAU88C22_RIGHT_DAC_DIGITAL_VOLUME,
	NAU88C22_LEFT_ADC_DIGITAL_VOLUME,
	NAU88C22_RIGHT_ADC_DIGITAL_VOLUME,
	NAU88C22_LEFT_INP_PGA_CONTROL,
	NAU88C22_RIGHT_INP_PGA_CONTROL,
	NAU88C22_LOUT1_HP_CONTROL,
	NAU88C22_ROUT1_HP_CONTROL,
	NAU88C22_LOUT2_SPK_CONTROL,
	NAU88C22_ROUT2_SPK_CONTROL,
};


void nau88c22_WriteReg(unsigned char reg_index, unsigned short value)
{ 
   unsigned char buf[2];
   buf[0] = ((reg_index << 1)  | (value >> 8));
   buf[1] = (unsigned char)(value & 0x00FF);
   i2c_write(SLAVE_ADDR, buf, 2, 1);
}

unsigned short nau88c22_ReadReg(unsigned char reg_index)
{
  unsigned char buf[3];
  buf[0] = reg_index<<1;

  i2c_write(SLAVE_ADDR, buf, 1, 0);
  i2c_read(SLAVE_ADDR, buf + 1, 2);
  return ((buf[1]<<8) | buf[2]);
}

void format(int rate, char count, char length) {
    int  clockControl;
    char monoOperationEnable;
    char wordLength;
    char mClkDiv;
    char bClkDiv;
    int  audioInterface = 0x010;
    
    if (count >= 2) {
        monoOperationEnable = 0x0;
    } else {
        /* FIXME */
	    //count =2;
        monoOperationEnable = 0x1;
    }
    audioInterface = (audioInterface & 0x1FE) | monoOperationEnable;
    
    if (length == 16) {
        wordLength = 0x0;
    } else if (length == 32) {
        wordLength = 0x3;
    } else {
        /* FIXME */
        wordLength = 0x3;
    }
    audioInterface = (audioInterface & 0x19F) | (wordLength << 5);
    
    if (rate % 11025) {
        nau88c22_WriteReg(36, 0x008);    //12.288Mhz
        nau88c22_WriteReg(37, 0x00C);
        nau88c22_WriteReg(38, 0x093);
        nau88c22_WriteReg(39, 0x0E9);
        /* FIXME */
        if (rate > 48000)
            rate = 8000;
        mClkDiv = (48000 * 256 * 2) / (rate * 256);
        bClkDiv = (rate * 256) / (rate * count * length);
    } else {
        nau88c22_WriteReg(36, 0x007);    //11.2896Mhz
        nau88c22_WriteReg(37, 0x021);
        nau88c22_WriteReg(38, 0x161);
        nau88c22_WriteReg(39, 0x026);
        /* FIXME */
        if (rate > 44100)
            rate = 11025;
        mClkDiv = (44100 * 256 * 2) / (rate * 256);
        bClkDiv = (rate * 256) / (rate * count * length);
    }
    
    switch (mClkDiv) {
        case 1:
            mClkDiv = 0;
            break;
        case 2:
            mClkDiv = 2;
            break;
        case 3:
            mClkDiv = 3;
            break;
        case 4:
            mClkDiv = 4;
            break;
        case 6:
            mClkDiv = 5;
            break;
        case 8:
            mClkDiv = 6;
            break;
        case 12:
            mClkDiv = 7;
            break;
    }
    
    switch (bClkDiv) {
        case 1:
            bClkDiv = 0;
            break;
        case 2:
            bClkDiv = 1;
            break;
        case 4:
            bClkDiv = 2;
            break;
        case 8:
            bClkDiv = 3;
            break;
        case 16:
            bClkDiv = 4;
            break;
        case 32:
            bClkDiv = 5;
            break;
    }
    
    clockControl = 0;
    //clockControl = (clockControl & 0x0FF);
    //clockControl = (clockControl & 0x1FE);
   
    clockControl = (clockControl & 0x11F) | (mClkDiv << 5);
    clockControl = (clockControl & 0x1E3) | (bClkDiv << 2);
    
    nau88c22_WriteReg(4,  audioInterface);   
    nau88c22_WriteReg(6,  clockControl);

	clockControl = nau88c22_ReadReg(6);
	//fLib_printf("****audioInterface is 0x%x, clockControl is 0x%x\r\n",audioInterface,clockControl);
	
}

void nau88c22_init(void)
{
	fLib_printf("Initializing nau88c22...\r\n");
	//Software Reset
	nau88c22_WriteReg(0,  0);

    //[test/Power Management] 
    nau88c22_WriteReg(1,  0x1ed);
	nau88c22_WriteReg(2,  0x1bf);
	nau88c22_WriteReg(3,  0x1ef);

    //[test/Audio Control] 
    nau88c22_WriteReg(4,  0x11); //I2S format, 16bit audio
    nau88c22_WriteReg(5,  0x0);
	nau88c22_WriteReg(6,  0x6c);
	nau88c22_WriteReg(7,  0x6);
	nau88c22_WriteReg(8,  0x0);
	nau88c22_WriteReg(9,  0x0);
	nau88c22_WriteReg(0xa, 0xc);
	nau88c22_WriteReg(0xb, 0xff);
	nau88c22_WriteReg(0xc, 0xff);
	nau88c22_WriteReg(0xd, 0x0);
	nau88c22_WriteReg(0xe, 0x108);
	nau88c22_WriteReg(0xf, 0xff);
	nau88c22_WriteReg(0x10, 0xff);
	nau88c22_WriteReg(0x11, 0x6);

    //[test/Equalizer] 
	nau88c22_WriteReg(0x12, 0x12c);
	nau88c22_WriteReg(0x13, 0x2c);
	nau88c22_WriteReg(0x14, 0x2c);
	nau88c22_WriteReg(0x15, 0x2c);
	nau88c22_WriteReg(0x16, 0x2c);
	
    //[test/DAC Limiter] 
	nau88c22_WriteReg(0x18, 0x32);
	nau88c22_WriteReg(0x19, 0x0);

    //[test/Notch Filter] 
	nau88c22_WriteReg(0x1b, 0x0);
	nau88c22_WriteReg(0x1c, 0x0);
	nau88c22_WriteReg(0x1d, 0x0);
	nau88c22_WriteReg(0x1e, 0x0);

	//[test/ALC Control] 
	nau88c22_WriteReg(0x20, 0x38);
	nau88c22_WriteReg(0x21, 0xb);
	nau88c22_WriteReg(0x22, 0x32);
	nau88c22_WriteReg(0x23, 0x10);

    //[test/PLL Control] 
    nau88c22_WriteReg(0x24, 0x8);
	nau88c22_WriteReg(0x25, 0xc);
	nau88c22_WriteReg(0x26, 0x93);
	nau88c22_WriteReg(0x27, 0xe9);
	
    //[test/Mic Bias Mode] 
	nau88c22_WriteReg(0x28, 0x0);
	//[test/3D Control] 
	nau88c22_WriteReg(0x29, 0x0);

    //[test/Input Output Mixer] 
	nau88c22_WriteReg(0x2b, 0x10);
	nau88c22_WriteReg(0x2c, 0x30);
	nau88c22_WriteReg(0x2d, 0x50);//
	nau88c22_WriteReg(0x2e, 0x50);//
	nau88c22_WriteReg(0x2f, 0x100);
	nau88c22_WriteReg(0x30, 0x100);
	nau88c22_WriteReg(0x31, 0x43);
	nau88c22_WriteReg(0x32, 0x1);
	nau88c22_WriteReg(0x33, 0x0);
	nau88c22_WriteReg(0x34, 0x65);//
	nau88c22_WriteReg(0x35, 0x65);//
	nau88c22_WriteReg(0x36, 0x39);
	nau88c22_WriteReg(0x37, 0x39);
	nau88c22_WriteReg(0x38, 0x40);
	nau88c22_WriteReg(0x39, 0x40);
	nau88c22_WriteReg(0x3a, 0x0);

    //[test/PCM Timeslot] 
	nau88c22_WriteReg(0x3b, 0x0);
	nau88c22_WriteReg(0x3c, 0x20);
	nau88c22_WriteReg(0x3d, 0x20);
	nau88c22_WriteReg(0x3e, 0x7f);


    #if 0
	int Reg, Val;
	for(Reg = 0; Reg <= 79; Reg++){
		if((Reg > 63) && (Reg <70))
			continue;
		
		Val = nau88c22_ReadReg(Reg);
		fLib_printf("Reg 0x%0X = 0x%03X\r\n", Reg, Val);
	}
	#endif
}


